﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using RMH.Entities;

namespace RMH.Entities
{
	public class OccupancyReportResult
	{
		public IList<Room> Rooms { get; set; }
		public IList<Stay> Stays { get; set; }
		public DateTime StartDate { get; set; }
		public DateTime EndDate { get; set; }

		private IList<OccupancyReportAggregate> _roomMonths;
		public IList<OccupancyReportAggregate> RoomMonths { 
			get{
				if (_roomMonths == null)
					_roomMonths = Aggregate();
				return _roomMonths;
			} 
		}

		private IList<OccupancyReportAggregate> Aggregate() {
			List<OccupancyReportAggregate> list = new List<OccupancyReportAggregate>();
			DateTime stepdate = StartDate; // .AddHours(-16); // 8:00am rule
			while (stepdate < EndDate) {
				string month = stepdate.Year.ToString() + "-" + stepdate.Month.ToString();
				// remember the 8:00 am rule..
				OccupancyReportAggregate aggregate = new OccupancyReportAggregate() { Month = month, FirstDayOfMonth = stepdate.Date.AddDays(-stepdate.Date.Day+1).AddHours(8) };
				list.Add(aggregate);
				stepdate = stepdate.AddMonths(1);
			}

			foreach (OccupancyReportAggregate aggregate in list) {
				foreach (Room room in Rooms.Where(s=> aggregate.LastDayOfMonth >= s.StartDate)) {
					TimeSpan span = (aggregate.LastDayOfMonth - (room.StartDate > aggregate.FirstDayOfMonth ? room.StartDate : aggregate.FirstDayOfMonth));
					// add 16:30 hours to account for the 8:00 am rule...
					span = span.Add(new TimeSpan(16, 0, 0));
					aggregate.StayTotalCapacity += span.Days;
					foreach (Stay stay in Stays.Where(s => 
						((aggregate.FirstDayOfMonth <= s.CheckinDate && aggregate.LastDayOfMonth >= s.CheckinDate) || (aggregate.FirstDayOfMonth <= s.CheckoutDate && aggregate.LastDayOfMonth >= s.CheckoutDate))
						&& s.Room.Equals(room))) {

						//if (stay.Room != room) continue;
						DateTime endOfDateSpan = stay.CheckoutDate.HasValue ? stay.CheckoutDate.Value : aggregate.LastDayOfMonth;
						if (endOfDateSpan > aggregate.LastDayOfMonth) endOfDateSpan = aggregate.LastDayOfMonth;
						if (endOfDateSpan > DateTime.Now) endOfDateSpan = DateTime.Now;

						TimeSpan staySpan = (endOfDateSpan - stay.CheckinDate.Value);
						// add 16 hours to account for the 8:00am rule
						staySpan = staySpan.Add(new TimeSpan(16, 0, 0));
						if (stay.Type != OccupancyType.Patient)
							aggregate.StayTotalCapacity -= staySpan.Days;
						else
							aggregate.StayActual += staySpan.Days;
					

					}
				}
			}

			return list;
		}

	}

	public class OccupancyReportAggregate
	{
		public string Month { get; set; }
		internal DateTime FirstDayOfMonth { get; set; }
		internal DateTime LastDayOfMonth { 
			get {
				return FirstDayOfMonth.AddMonths(1); //.AddDays(-1);
				} 
		}
		public int StayTotalCapacity { get; set; }
		public int StayActual { get; set; }
		public float StayUtilization {
			get {
				return ((float)StayActual / (float) StayTotalCapacity * 100f);
			}
		}
	}
}
